package com.mcarthur.countdown.client.drawable;

import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.Stack;

public abstract class AbstractBallAnimator implements BallAnimator {
    protected static final float KINETIC_DAMPER = -0.9f;
    protected static final float KINETIC_DAMPER_X = 0.96f;
    
    protected List<BouncyBall> collidedBalls;
    protected Queue<BouncyBall> activeBalls;
    protected Stack<BouncyBall> inactiveBalls;
    
    public AbstractBallAnimator() {
        this(null,null);
    }
    
    public AbstractBallAnimator(Queue<BouncyBall> activeBalls, Stack<BouncyBall> inactiveBalls) {
        this.activeBalls = activeBalls;
        this.inactiveBalls = inactiveBalls;
        collidedBalls = new ArrayList<BouncyBall>();
    }
    
    protected void checkCollision(BouncyBall ball) {
        
        // BEGIN INSANE PHYSICS
        
        for (BouncyBall other : activeBalls) {
            if (ball == other || collidedBalls.contains(other)) {
                continue;
            }
            
            Vector2 axis = ball.getCenter().sub(other.getCenter());
            if (axis.getMagnitude() < (Ball.WIDTH)) {
                // collision!
                axis = axis.getUnit();
                
                Vector2 b1 = new Vector2(ball.getVelX(), ball.getVelY());
                Vector2 b1x = axis.mult((axis.dot(b1)));
                Vector2 b1y = b1.sub(b1x);
                
                Vector2 b2 = new Vector2(other.getVelX(), other.getVelY());
                Vector2 negAxis = axis.mult(-1);
                Vector2 b2x = negAxis.mult(negAxis.dot(b2));
                Vector2 b2y = b2.sub(b2x);
                
                Vector2 v1x = (b2x.mult(2)).mult(0.5f);
                Vector2 v2x = (b1x.mult(2)).mult(0.5f);
                
                Vector2 v1y = b1y;
                Vector2 v2y = b2y;

                Vector2 v1 = v1x.add(v1y);
                Vector2 v2 = v2x.add(v2y);
                
                ball.setVelX(v1.x);
                ball.setVelY(v1.y);
                
                other.setVelX(v2.x);
                other.setVelY(v2.y);
            }
        }
        
        collidedBalls.add(ball);

        // END
    }
    
    protected void checkBounds(BouncyBall ball) {
        // Concurrent mod exception ;-( might not be needed tho
//        if (ball.getPosX() <= -Ball.WIDTH || ball.getPosX() >= CountdownRenderer.viewWidth) {
//
//        }
        
        if (ball.getPosY() < 0) {
            ball.setPosY(0.f);
            ball.setVelY(ball.getVelY() * KINETIC_DAMPER);
            ball.setVelX(ball.getVelX() * KINETIC_DAMPER_X);
        }
    }
    
    @Override
    public void setInactiveBalls(Stack<BouncyBall> inactiveBalls) {
        this.inactiveBalls = inactiveBalls;
    }
    
    @Override
    public void setActiveBalls(Queue<BouncyBall> activeBalls) {
        this.activeBalls = activeBalls;
    }
}
